<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | 账户表
// +----------------------------------------------------------------------
namespace app\sso\model;

use Inphp\Core\Db\Db;
use Inphp\Core\Db\PDO\Model;
use Inphp\Core\Util\Str;

class UserModel extends Model
{
    /**
     * 表名
     * @var string
     */
    protected string $tableName = "sso_user";

    /**
     * 主键字段
     * @var string
     */
    protected string $primaryKey = "uid";

    /**
     * 编码昵称
     * @param string $string
     * @return string
     */
    public static function encodeNickname(string $string): string
    {
        return "data:text/plant;base64,".base64_encode($string);
    }

    /**
     * 解码昵称
     * @param string|null $nickname
     * @return string|null
     */
    public static function decodeNickname(?string $nickname): ?string
    {
        if (empty($nickname)) {
            return null;
        }
        if (stripos($nickname, "data:text/plant;base64,") === 0) {
            $nickname = base64_decode(substr($nickname, 23));
        }
        return $nickname;
    }

    /**
     * 登陆密码加密
     * @param string $password
     * @return array
     */
    public static function hashLoginPassword(string $password): array
    {
        $pwdKey = Str::randomString(6);
        $password = md5(md5($password).$pwdKey);
        return [$password, $pwdKey];
    }

    /**
     * 验证登陆密码
     * @param string $password
     * @param string $pwdKey
     * @param string $hash
     * @return bool
     */
    public static function verifyLoginPassword(string $password, string $pwdKey, string $hash): bool
    {
        return md5(md5($password).$pwdKey) === $hash;
    }

    /**
     * 验证安全操作密码
     * @param string $password
     * @param int $uid
     * @return bool
     */
    public static function verifySafePassword(string $password, int $uid): bool
    {
        $user = self::getRowByPrimaryKey($uid);
        if (empty($user)) {
            return false;
        }
        return !empty($user["sp"]) && md5(md5($password).$user["uid"]) === $user["sp"];
    }

    /**
     * 验证安全操作密码
     * @param string $password
     * @param array $user
     * @return bool
     */
    public static function verifySPByUser(string $password, array $user): bool
    {
        return !empty($user["sp"]) && md5(md5($password).$user["uid"]) === $user["sp"];
    }

    /**
     * 加密安全操作密码
     * @param string $password
     * @param int $uid
     * @return string
     */
    public static function hashSP(string $password, int $uid): string
    {
        return md5(md5($password).$uid);
    }

    /**
     * 检测用户名是否合法可用
     * @param string|null $value
     * @param int $uid
     * @return bool
     */
    public static function checkUsername(?string $value, int $uid = 0): bool
    {
        if (empty($value)) {
            return false;
        }
        //不允许纯数字
        if (is_numeric($value)) {
            return false;
        }
        //检测合法性
        if (!Str::isLUN($value)) {
            return false;
        }
        //检测是否在存在系统中
        $exists = self::emptyQuery()
            ->where("username", $value)
            ->where("uid", "!=", $uid)
            ->first();
        return empty($exists);
    }

    /**
     * 判断权限
     * @param string|array|null $need
     * @param array|null $belongPermissionList
     * @return bool
     */
    public static function matchPermission(string|array|null $need, ?array $belongPermissionList = null): bool
    {
        if (empty($need)) {
            return true;
        }
        if (empty($belongPermissionList)) {
            return false;
        }
        $bool = false;
        $needPermissionList = is_array($need) ? $need : explode(",", $need);
        $break1 = false;
        foreach ($needPermissionList as $pathValue) {
            //
            if ($break1) {
                break;
            }
            //只要其中一个PATH通过，即可
            $pathArray = explode("/", Str::trim($pathValue));
            //遍历
            $break2 = false;
            foreach ($belongPermissionList as $permissionList) {
                if ($break2) {
                    break;
                }
                $p = $permissionList;
                //通过路径查找匹配
                foreach ($pathArray as $path) {
                    if (empty($path)) {
                        continue;
                    }
                    $b = $p[$path] ?? null;
                    if (is_array($b)) {
                        //属性一个数组，往下级找
                        $p = $b;
                        continue;
                    }
                    if (is_null($b)) {
                        break;
                    }
                    if ($b === true) {
                        $bool = $b;
                        $break1 = true;
                        $break2 = true;
                        break;
                    }
                }
            }
        }
        return $bool;
    }

    /**
     * 根据归属分组，判断所需权限
     * @param string|array|null $need
     * @param string|null $groups
     * @return bool
     */
    public static function matchPermissionByGroups(string|array|null $need, ?string $groups): bool
    {
        if (empty($need)) {
            return true;
        }
        if (!empty($groups)) {
            $userBelongPermissions = [];
            $userBelongGroups = Db::from("sso_group")
                ->whereIn("id", $groups)
                ->get();
            foreach ($userBelongGroups as $group) {
                if (!empty($group["permission"])) {
                    $userBelongPermissions[] = @json_decode($group["permission"], true) ?? [];
                }
            }
            if (!empty($userBelongPermissions)) {
                return self::matchPermission($need, $userBelongPermissions);
            }
        }
        return false;
    }
}